﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace VirtualDisk
{
    class DiskTree
    {
        
        private static DiskTree _instance;
        //根目录
        private DirectoryNode root;
        //当前目录
        private DirectoryNode pwd;
        private DiskTree()
        {
            root = new DirectoryNode(new MyString("C:"), DateTime.Now);
            pwd = root;
            

        }

        public static DiskTree getInstance()
        {
            if (_instance == null)
            {
                _instance = new DiskTree();
            }
            return _instance;

        }

        //以path为路径创建一个目录
        public void createNode(MyString path)
        {
            DiskNode temp = null;
            int i;
            MyString[] NamesInPath = path.Split(new char[]{'\\'},StringSplitOptions.RemoveEmptyEntries);
            MyString name = NamesInPath[NamesInPath.Length - 1];
            if (DiskHelper.isAbsolutePath(path))
            {
                temp = root;
                i = path.IndexOf('\\') == 0 ? 0 : 1;
            }
            else
            {
                temp = pwd;
                i = 0;

            }
            bool flag = true;
            DiskNode nodeFlag = null;
            for (; i < NamesInPath.Length; i++)
            {
                if (flag)
                {
                    nodeFlag = temp.getNode(NamesInPath[i]);
                    if (nodeFlag == null)
                    {
                        flag = false;
                        DirectoryNode newNode = new DirectoryNode(NamesInPath[i], DateTime.Now);
                        temp.addNode(newNode);
                        temp = newNode;
                    }
                    else
                        temp = nodeFlag;
                 }
                else
                {
                    DirectoryNode newNode = new DirectoryNode(NamesInPath[i], DateTime.Now);
                    temp.addNode(newNode);
                    temp = newNode;
                } 
            }
        }
        //通过拷贝source路径的文件，在des目录创建同名节点
        public void createNodeByCopy(MyString des, MyString source)
        {
            DiskNode parent = searchNode(des);
            if (parent!=null)
            {
                using (FileStream fs = new FileStream(source.ToString(), FileMode.Open, FileAccess.Read))
                {
                    MyString name = DiskHelper.getFileName(source);
                    FileNode child = new FileNode(name, DateTime.Now);
                    child.setData(fs);
                    parent.addNode(child);

                }
                
                
            }
        }
        //删除path为路径的目录或文件
        public void removeNode(MyString path)
        {
            DiskNode nodeTemp = searchNode(path);
            nodeTemp.Parent.removeNode(nodeTemp);
        }
        //使用通配符删除文件
        public void removeNodeByWildcard(MyString path)
        {
            List<DiskNode> nodes = searchNodesByWildcard(path);
            foreach (DiskNode node in nodes)
            {
                node.Parent.removeNode(node);
            }
        }
        //判断目录是否为空
        public bool isEmptyDirctory(MyString path)
        {
            DiskNode nodeTemp = searchNode(path);
            return (nodeTemp as DirectoryNode).Children.Count==0;
        }
        //没有判断是否为目录
        public bool isADirctory(MyString path)
        {
            DiskNode node = searchNode(path);
            if (node != null)
                return (node is DirectoryNode);
            else
                return false;
        }

        public bool HasRelationship(MyString parentPath, MyString childPath)
        {
            DiskNode parent = searchNode(parentPath);
            DiskNode child = searchNode(childPath);
            if (child==null||parent==null)
            {
                return false;
            }
            else
            {
                return HasRelationship(parent, child);
            }
        }
        private bool HasRelationship(DiskNode parent, DiskNode child)
        {
            if (Object.ReferenceEquals(parent,child))
            {
                return true;
            }
           if (child.Parent!=null)
           {
               if (Object.ReferenceEquals(parent, child.Parent))
               {
                   return true;
               }
               if (parent is DirectoryNode)
               {
                   foreach (DiskNode c in (parent as DirectoryNode).Children)
                   {
                       if (HasRelationship(c, child))
                           return true;
                   }
               }
           }
           return false;
        }

        //打印path为路径的节点的所有信心，包括节点的名字、类型、创建时间和所有直接子节点的这些信息

        public void showNodeInfo(MyString path, DiskNode.ShowOptions option)
        {
            DiskNode nodeTemp = searchNode(path);
            if(nodeTemp!=null)
                showNodeInfo(nodeTemp, option);
        }
        private void showNodeInfo(DiskNode nodeTemp, DiskNode.ShowOptions option)
        {
            nodeTemp.showInfo(option);          
        }
        private void showAllNodeInfo(DiskNode nodeTemp,DiskNode.ShowOptions option)
        {
            nodeTemp.showAllInfo(option);  
        }
        public void showAllNodeInfo(MyString path, DiskNode.ShowOptions option)
        {
                DiskNode nodeTemp = searchNode(path);
                if (nodeTemp != null)
                    showAllNodeInfo(nodeTemp,option);
        }

        //读取path文件的数据
        public Byte[] readFileData(MyString path)
        {
            DiskNode nodetemp = searchNode(path);
            if (nodetemp != null && nodetemp is FileNode)
            {
                return (nodetemp as FileNode).FileData;
            }
            else
                return null;
        }

        //将source文件的数据写入path文件中
        public void writeFileData(MyString path, MyString source)
        {
            DiskNode nodeTemp = searchNode(path);
            if (nodeTemp!=null)
            {
                using (FileStream fs = new FileStream(source.ToString(), FileMode.Open, FileAccess.Read))
                {
                    (nodeTemp as FileNode).setData(fs);
                }
            }
        }
        

        
       //更改当前目录路径
        public void changePWD(MyString path)
        {
            DiskNode nodeTemp = searchNode(path);
            if (nodeTemp != null)
            {
                if (nodeTemp is DirectoryNode)
                {
                    pwd = nodeTemp as DirectoryNode;
                } 
            }
        }

       
        //获得当前目录路径
        public MyString getPWDPath()
        {
            return pwd.getPath();
        }
        //获得根目录路径
        public MyString getRootPath()
        {
            return root.Name;
        }

        //以path为路径搜索节点，存在返回该节点，不存在返回null
        private DiskNode searchNode(MyString path)
        {

            DiskNode temp = null;
            int i;
            MyString[] NamesInPath = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            if (DiskHelper.isAbsolutePath(path))
            {
                temp = root;
                i = path.IndexOf('\\') == 0 ? 0 : 1;
            }
            else
            {
                temp = pwd;
                i = 0;

            }
            for (; i < NamesInPath.Length; i++)
            {
                temp = temp.getNode(NamesInPath[i]);
                if (temp==null)
                {
                    break;
                }
              
            }
            return temp;
        }

        private List<DiskNode> searchNodesByWildcard(MyString path)
        {
            List<DiskNode> nodes = new List<DiskNode>();
            MyString parentPath = DiskHelper.getDirectoryName(path);
            MyString wildcardName = DiskHelper.getFileName(path);
            DiskNode parent = searchNode(parentPath);
            if (parent != null)
            {
                List<MyString> names = getAllFNodeByWildcard(parent, wildcardName);
                DiskNode child = null;
                foreach (MyString name in names)
                {
                    child = searchNode(name);
                    nodes.Add(child);
                }
            }
            return nodes;
        }
        private List<MyString> getAllFNodeByWildcard(DiskNode node, MyString wildcardName)
        {
            List<MyString> realnames = new List<MyString>();
            MyString correctName = DiskHelper.getCorrectWildcradName(wildcardName);
            Regex re = new Regex(correctName.ToString());
            if (node is DirectoryNode)
            {
                foreach (DiskNode child in (node as DirectoryNode).Children)
                {
                    if (re.IsMatch(child.Name.ToString()))
                    {
                        if (child is FileNode)
                        {
                            realnames.Add(child.getPath());
                        }

                    }

                }
            }
            return realnames;
        }

        
        //判断path路径是否存在
        public bool isExist(MyString path)
        {
            MyString wildcardName = DiskHelper.getFileName(path);
            if (path.IndexOfAny(new char[]{'?','*'})!=-1)
            {
                List<DiskNode> nodesTemp=searchNodesByWildcard(path);
                if (nodesTemp.Count!=0)
                {
                    return true;
                }
                else
                    return false;
            }
            else
            {
                DiskNode temp = searchNode(path);
                if (temp != null)
                {
                    return true;
                }
                else
                    return false;
                }
           

        }
    }
}
